Introduction

The distributions of annual peak flows at USGS streamgages are used estimate flood frequency-magnitude characteristics at gaged sites by use of the log-Peason type-III distribution. This distribution is described by measures of the mean, variance, and skewness of the logarithm of annual peak flows. Estimates of high magnitude floods are particularly sensitive to the skewness of the distribution, although skewness estimates based on data from an individual streamgage are highly variable. Based on guidelines provided in Bulletin 17B and 17C, a regional estimate of flood skew is combined with an at-site (station skew) estimate to help stabilize the estimate of flood frequency characteristics.

A Bayesian generalized least squares (B-GLS) model is the standard approach for estimating the regional skew by regression on basin and climatic characteristics. This approach accounts for the length of record and spatial correlations among contemporaneous annual peaks in a network of streamgages by appropriately adjusting model parameters and uncertainty estimates. Despite the capabilities of the underlying model, identifying individual basin or climatic characteristics that are statistically associated with flood skew is problematic. Therefore, a constant is commonly used to estimate regional skew under the B-GLS model.

It may be the case, however, that subtle spatial variations in regional skew are caused by a combination of factors that are not linearly associated with available basin or climatic characteristics. Such effects may result in a persistent spatial pattern in the residuals of the skew estimates. To assess this possibility, a generalized additive model (GAM) is applied to the skew residuals from a B-GLS analysis of two, two-digit hydrologic regions, which includes US Great Lakes (04) and the Ohio River (05) basins. The GAM model provides a flexible basis of smoothing functions to accommodate irregular variations in covariates, such as spatial coordinates of gaged basin centroids. Linear components also are accommodated in a GAM model.

Computed station skew statistics from 368 streamgages in hydrologic unit regions 04 and 05 with 35 or more years of annual peak flow data were used in this analysis. Station skews were computed by use of methods described in Bulletin 17C. A preliminary analysis of the data describes the spatial distribution of gaged basin centroids, and analyzes the distribution of station skew values for outliers. A GAM model was fit to the skew values using the eastings and northing of basin centroids to provide an initial assessment of the potential utility of the GAM model. Within the GAM analysis, station-skews for individual streamgages will be weighted by their record length. This preliminary assessment was followed by repeated, random partitioning of the data set into training and testing subsets containing 80- and 20-percent of the full data set, respectively. The testing data set was used to determine whether the GAM model outperformed the constant estimated by use of the B-GLS model.

Initialize Environment

library(tidyverse)
-- Attaching packages --------------------------------------- tidyverse 1.2.0 --
v ggplot2 2.2.1     v purrr   0.2.4
v tibble  1.3.4     v dplyr   0.7.4
v tidyr   0.7.2     v stringr 1.2.0
v readr   1.1.1     v forcats 0.2.0
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(knitr)

Read in Skew Data for HUC Regions 04 and 05

df <- read_tsv(file = 'C:/Home/SW_Specialist/Skew0405/data/skew_data.txt') %>% 
   mutate(Station = paste0('0',USGS),
          Resid_skew_sign = factor(sign(Residuals))) %>% 
   rename(Record_len      = Pseudo_Length,
          Station_skew    = Station_Skew,
          Residual_skew   = Residuals) 
Parsed with column specification:
cols(
  Index = col_integer(),
  USGS = col_integer(),
  Pseudo_Length = col_integer(),
  Station_Skew = col_double(),
  log10_DA = col_double(),
  Lat_Cntrd = col_double(),
  Long_Cntrd = col_double(),
  Residuals = col_double()
)

List Subset of Data and Summarize

kable(df[1:20,c('Station','Station_skew','Residual_skew','Lat_Cntrd','Long_Cntrd')],
      caption = 'Sample of Skew Residual Data')
Station Station_skew Residual_skew Lat_Cntrd Long_Cntrd
03336645 0.419 0.332 40.39385 -88.00935
03336900 0.000 -0.086 40.25089 -88.07321
03343400 -0.736 -0.822 39.92401 -88.14127
03344500 0.102 0.016 39.34818 -88.00714
03345500 -0.827 -0.913 39.51656 -88.13700
03346000 -0.304 -0.390 39.26853 -87.91700
03378000 -0.456 -0.542 38.53839 -87.94023
03378635 0.334 0.248 39.30351 -88.52165
03379500 -0.599 -0.686 38.99769 -88.48511
03380500 -0.037 -0.123 38.56331 -88.72489
03381500 0.239 0.153 38.64497 -88.44497
03382100 1.739 1.653 37.61436 -88.85263
03384450 -0.355 -0.441 37.53137 -88.52718
03385000 -0.231 -0.317 37.47848 -88.61897
03274650 -1.257 -1.343 40.04106 -85.10903
03275000 -0.360 -0.446 39.84952 -85.09757
03275600 -0.210 -0.297 39.86655 -84.84453
03276700 0.518 0.431 39.08198 -85.11773
03277000 0.076 -0.010 39.13191 -85.21422
03291780 -0.639 -0.725 38.93353 -85.28100

Plot Distribution of Streamgage Centrois

Note: symbols discretize residuals into positive and negative values

us_map %>% 
   filter(region %in% c('michigan', 'ohio', 'indiana', 'wisconsin', 'illinois',
                        'pennsylvania','new york', 'kentucky', 'west virginia',
                        'vermont')) %>% 
   ggplot( aes(x = long, y = lat, group = group)) + 
   geom_polygon(fill = 'tan', color = 'black') + 
   geom_polygon(data = huc2_0405, aes(x = long, y = lat, group = group),
                fill = NA, color = 'blue') +
   geom_point(  data = df, aes( x = Long_Cntrd, y = Lat_Cntrd, group = NULL), 
                color = 'red') + 
   coord_map('conic', lat0 = 42)
Regions defined for each Polygons


Project Latitudes and Longitudes of Basin Centroids

library(rgdal)
library(sp)
df_prj  <- df
coordinates(df_prj) <- c('Long_Cntrd', 'Lat_Cntrd')
class(df_prj)
[1] "SpatialPointsDataFrame"
attr(,"package")
[1] "sp"
proj4string(df_prj) <- "+proj=longlat +datum=NAD83"
# Same transform as 
#  EPSG:102003 USA_Contiguous_Albers_Equal_Area_Conic'
proj_sel <-  'EPSG:102004 USA_Contiguous_Lambert_Conformal_Conic'
#  EPSG:102005 USA_Contiguous_Equidistant_Conic
df_prj <- spTransform(df_prj, CRS = CRS("+init=esri:102004"))
easting  <- attributes(df_prj)$coords[,1]
northing <- attributes(df_prj)$coords[,2]
plot(easting, northing, pch = 16, col = 'blue')

east_std <- (easting  - mean(easting ))/100000
nrth_std <- (northing - mean(northing))/100000
plot(east_std, nrth_std, pch = 16, col = 'green4',
     main = paste('Regional Skew Streamgages',proj_sel),
     xlab = 'Standardized Easting', ylab = 'Standardized Northing')

df %>%
   ggplot( aes( x = Station_skew)) +
   geom_histogram() + 
   geom_vline( xintercept = 0, color = 'red', linetype = 'dashed')

ndxOut <- which(df$Station_skew > 2)
# Remove outlier
df <- df[-ndxOut,]
df %>%
   ggplot( aes( x = Station_skew)) +
   geom_freqpoly( aes(y = ..density..), color = 'salmon', size = 1.2) + 
   geom_vline( xintercept = 0, color = 'red', linetype = 'dashed') +
   stat_function(fun = dnorm, args = list(mean = mean(df$Station_skew),
                                          sd   =   sd(df$Station_skew)),
                 color = 'blue') +
   theme_few()

library(mgcv)
df$east <- east_std[-ndxOut]
df$nrth <- nrth_std[-ndxOut]
gam1 <- gam(Station_skew ~ s(east, nrth), weights = Record_len, data = df)
summary(gam1)

Family: gaussian 
Link function: identity 

Formula:
Station_skew ~ s(east, nrth)

Parametric coefficients:
            Estimate Std. Error t value Pr(>|t|)   
(Intercept)  0.07062    0.02185   3.231  0.00135 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Approximate significance of smooth terms:
               edf Ref.df     F  p-value    
s(east,nrth) 24.42  27.72 3.847 7.74e-10 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

R-sq.(adj) =  0.215   Deviance explained = 26.8%
GCV = 12.151  Scale est. = 11.307    n = 366
plot(gam1)

df$gam_resid <- gam1$residuals
df %>% 
   ggplot( aes(x = gam_resid) ) +
   geom_density(colour = 'red', size = 1.5) +
   geom_density( aes(x = Residual_skew), color = 'blue', size = 1.5) +
   theme_few() 

us_map %>% 
   filter(region %in% c('michigan', 'ohio', 'indiana', 'wisconsin', 'illinois',
                        'pennsylvania','new york', 'kentucky', 'west virginia',
                        'vermont')) %>% 
   ggplot( aes(x = long, y = lat, group = group)) + 
   geom_polygon(fill = 'tan', color = 'black') + 
   coord_map('conic', lat0 = 42) +
   # theme_void() + # This eliminates lat/lon marks 
   # theme_few() +
   geom_point(data = df, aes( x=Long_Cntrd, y = Lat_Cntrd, 
                              colour = gam_resid, group = NULL)) +
   scale_colour_gradient2(low  = "red" , mid = "white",
                          high = "blue" )

Skew Contour Map

A skew contour map is developed that is based on the gam1 model above.

plot_ly( x = c(xvec), y = c(yvec),
   z = matrix(zvec,40,40, byrow = TRUE), type = 'contour', 
   contours = list(start = -0.5, end = 0.7, size = 0.2, showlabels = TRUE)) %>% 
   add_trace(type = 'scatter', mode = 'markers', x = df$east, y = df$nrth, 
               color = 'red', hovertext = paste(df$Station, df$Station_skew)) 
'scatter' objects don't have these attributes: 'z', 'contours'
Valid attributes include:
'type', 'visible', 'showlegend', 'legendgroup', 'opacity', 'name', 'uid', 'ids', 'customdata', 'hoverinfo', 'hoverlabel', 'stream', 'x', 'x0', 'dx', 'y', 'y0', 'dy', 'text', 'hovertext', 'mode', 'hoveron', 'line', 'connectgaps', 'cliponaxis', 'fill', 'fillcolor', 'marker', 'textposition', 'textfont', 'r', 't', 'error_y', 'error_x', 'xaxis', 'yaxis', 'xcalendar', 'ycalendar', 'idssrc', 'customdatasrc', 'hoverinfosrc', 'xsrc', 'ysrc', 'textsrc', 'hovertextsrc', 'textpositionsrc', 'rsrc', 'tsrc', 'key', 'set', 'frame', 'transforms', '_isNestedKey', '_isSimpleKey', '_isGraticule'
'scatter' objects don't have these attributes: 'z', 'contours'
Valid attributes include:
'type', 'visible', 'showlegend', 'legendgroup', 'opacity', 'name', 'uid', 'ids', 'customdata', 'hoverinfo', 'hoverlabel', 'stream', 'x', 'x0', 'dx', 'y', 'y0', 'dy', 'text', 'hovertext', 'mode', 'hoveron', 'line', 'connectgaps', 'cliponaxis', 'fill', 'fillcolor', 'marker', 'textposition', 'textfont', 'r', 't', 'error_y', 'error_x', 'xaxis', 'yaxis', 'xcalendar', 'ycalendar', 'idssrc', 'customdatasrc', 'hoverinfosrc', 'xsrc', 'ysrc', 'textsrc', 'hovertextsrc', 'textpositionsrc', 'rsrc', 'tsrc', 'key', 'set', 'frame', 'transforms', '_isNestedKey', '_isSimpleKey', '_isGraticule'
LS0tDQp0aXRsZTogIlByZWxpbWluYXJ5IEFuYWx5c2lzIG9mIFNrZXcgUmVzaWR1YWxzIGluIEhVQ3MgMDQgYW5kIDA1Ig0KYXV0aG9yOiBEYXZlIEhvbHRzY2hsYWcNCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMjIEludHJvZHVjdGlvbg0KDQpUaGUgZGlzdHJpYnV0aW9ucyBvZiBhbm51YWwgcGVhayBmbG93cyBhdCBVU0dTIHN0cmVhbWdhZ2VzIGFyZSB1c2VkIGVzdGltYXRlIGZsb29kIGZyZXF1ZW5jeS1tYWduaXR1ZGUgY2hhcmFjdGVyaXN0aWNzIGF0IGdhZ2VkIHNpdGVzIGJ5IHVzZSBvZiB0aGUgbG9nLVBlYXNvbiB0eXBlLUlJSSBkaXN0cmlidXRpb24uICBUaGlzIGRpc3RyaWJ1dGlvbiBpcyBkZXNjcmliZWQgYnkgbWVhc3VyZXMgb2YgdGhlIG1lYW4sIHZhcmlhbmNlLCBhbmQgc2tld25lc3Mgb2YgdGhlIGxvZ2FyaXRobSBvZiBhbm51YWwgcGVhayBmbG93cy4gIEVzdGltYXRlcyBvZiBoaWdoIG1hZ25pdHVkZSBmbG9vZHMgYXJlIHBhcnRpY3VsYXJseSBzZW5zaXRpdmUgdG8gdGhlIHNrZXduZXNzIG9mIHRoZSBkaXN0cmlidXRpb24sIGFsdGhvdWdoIHNrZXduZXNzIGVzdGltYXRlcyBiYXNlZCBvbiBkYXRhIGZyb20gYW4gaW5kaXZpZHVhbCBzdHJlYW1nYWdlIGFyZSBoaWdobHkgdmFyaWFibGUuIEJhc2VkIG9uIGd1aWRlbGluZXMgcHJvdmlkZWQgaW4gQnVsbGV0aW4gMTdCIGFuZCAxN0MsIGEgcmVnaW9uYWwgZXN0aW1hdGUgb2YgZmxvb2Qgc2tldyBpcyBjb21iaW5lZCB3aXRoIGFuIGF0LXNpdGUgKHN0YXRpb24gc2tldykgZXN0aW1hdGUgdG8gaGVscCBzdGFiaWxpemUgdGhlIGVzdGltYXRlIG9mIGZsb29kIGZyZXF1ZW5jeSBjaGFyYWN0ZXJpc3RpY3MuICANCg0KQSBCYXllc2lhbiBnZW5lcmFsaXplZCBsZWFzdCBzcXVhcmVzIChCLUdMUykgbW9kZWwgaXMgdGhlIHN0YW5kYXJkIGFwcHJvYWNoIGZvciBlc3RpbWF0aW5nIHRoZSByZWdpb25hbCBza2V3IGJ5IHJlZ3Jlc3Npb24gb24gYmFzaW4gYW5kIGNsaW1hdGljIGNoYXJhY3RlcmlzdGljcy4gIFRoaXMgYXBwcm9hY2ggYWNjb3VudHMgZm9yIHRoZSBsZW5ndGggb2YgcmVjb3JkIGFuZCBzcGF0aWFsIGNvcnJlbGF0aW9ucyBhbW9uZyBjb250ZW1wb3JhbmVvdXMgYW5udWFsIHBlYWtzIGluIGEgbmV0d29yayBvZiBzdHJlYW1nYWdlcyBieSBhcHByb3ByaWF0ZWx5IGFkanVzdGluZyBtb2RlbCBwYXJhbWV0ZXJzIGFuZCB1bmNlcnRhaW50eSBlc3RpbWF0ZXMuIERlc3BpdGUgdGhlIGNhcGFiaWxpdGllcyBvZiB0aGUgdW5kZXJseWluZyBtb2RlbCwgaWRlbnRpZnlpbmcgaW5kaXZpZHVhbCBiYXNpbiBvciBjbGltYXRpYyBjaGFyYWN0ZXJpc3RpY3MgdGhhdCBhcmUgc3RhdGlzdGljYWxseSBhc3NvY2lhdGVkIHdpdGggZmxvb2Qgc2tldyBpcyBwcm9ibGVtYXRpYy4gIFRoZXJlZm9yZSwgYSBjb25zdGFudCBpcyBjb21tb25seSB1c2VkIHRvIGVzdGltYXRlIHJlZ2lvbmFsIHNrZXcgdW5kZXIgdGhlIEItR0xTIG1vZGVsLiAgDQoNCkl0IG1heSBiZSB0aGUgY2FzZSwgaG93ZXZlciwgdGhhdCBzdWJ0bGUgc3BhdGlhbCB2YXJpYXRpb25zIGluIHJlZ2lvbmFsIHNrZXcgYXJlIGNhdXNlZCBieSBhIGNvbWJpbmF0aW9uIG9mIGZhY3RvcnMgdGhhdCBhcmUgbm90IGxpbmVhcmx5IGFzc29jaWF0ZWQgd2l0aCBhdmFpbGFibGUgYmFzaW4gb3IgY2xpbWF0aWMgY2hhcmFjdGVyaXN0aWNzLiBTdWNoIGVmZmVjdHMgbWF5IHJlc3VsdCBpbiBhIHBlcnNpc3RlbnQgc3BhdGlhbCBwYXR0ZXJuIGluIHRoZSByZXNpZHVhbHMgb2YgdGhlIHNrZXcgZXN0aW1hdGVzLiAgVG8gYXNzZXNzIHRoaXMgcG9zc2liaWxpdHksIGEgZ2VuZXJhbGl6ZWQgYWRkaXRpdmUgbW9kZWwgKEdBTSkgaXMgYXBwbGllZCB0byB0aGUgc2tldyByZXNpZHVhbHMgZnJvbSBhIEItR0xTIGFuYWx5c2lzIG9mIHR3bywgdHdvLWRpZ2l0IGh5ZHJvbG9naWMgcmVnaW9ucywgd2hpY2ggaW5jbHVkZXMgVVMgR3JlYXQgTGFrZXMgKDA0KSBhbmQgdGhlIE9oaW8gUml2ZXIgKDA1KSBiYXNpbnMuIFRoZSBHQU0gbW9kZWwgcHJvdmlkZXMgYSBmbGV4aWJsZSBiYXNpcyBvZiBzbW9vdGhpbmcgZnVuY3Rpb25zIHRvIGFjY29tbW9kYXRlIGlycmVndWxhciB2YXJpYXRpb25zIGluIGNvdmFyaWF0ZXMsIHN1Y2ggYXMgc3BhdGlhbCBjb29yZGluYXRlcyBvZiBnYWdlZCBiYXNpbiBjZW50cm9pZHMuICBMaW5lYXIgY29tcG9uZW50cyBhbHNvIGFyZSBhY2NvbW1vZGF0ZWQgaW4gYSBHQU0gbW9kZWwuDQoNCkNvbXB1dGVkIHN0YXRpb24gc2tldyBzdGF0aXN0aWNzIGZyb20gMzY4IHN0cmVhbWdhZ2VzIGluIGh5ZHJvbG9naWMgdW5pdCByZWdpb25zIDA0IGFuZCAwNSB3aXRoIDM1IG9yIG1vcmUgeWVhcnMgb2YgYW5udWFsIHBlYWsgZmxvdyBkYXRhIHdlcmUgdXNlZCBpbiB0aGlzIGFuYWx5c2lzLiAgU3RhdGlvbiBza2V3cyB3ZXJlIGNvbXB1dGVkIGJ5IHVzZSBvZiBtZXRob2RzIGRlc2NyaWJlZCBpbiBCdWxsZXRpbiAxN0MuICBBIHByZWxpbWluYXJ5IGFuYWx5c2lzIG9mIHRoZSBkYXRhIGRlc2NyaWJlcyB0aGUgc3BhdGlhbCBkaXN0cmlidXRpb24gb2YgZ2FnZWQgYmFzaW4gY2VudHJvaWRzLCBhbmQgYW5hbHl6ZXMgdGhlIGRpc3RyaWJ1dGlvbiBvZiBzdGF0aW9uIHNrZXcgdmFsdWVzIGZvciBvdXRsaWVycy4gIEEgR0FNIG1vZGVsIHdhcyBmaXQgdG8gdGhlIHNrZXcgdmFsdWVzIHVzaW5nIHRoZSBlYXN0aW5ncyBhbmQgbm9ydGhpbmcgb2YgYmFzaW4gY2VudHJvaWRzIHRvIHByb3ZpZGUgYW4gaW5pdGlhbCBhc3Nlc3NtZW50IG9mIHRoZSBwb3RlbnRpYWwgdXRpbGl0eSBvZiB0aGUgR0FNIG1vZGVsLiBXaXRoaW4gdGhlIEdBTSBhbmFseXNpcywgc3RhdGlvbi1za2V3cyBmb3IgaW5kaXZpZHVhbCBzdHJlYW1nYWdlcyB3aWxsIGJlIHdlaWdodGVkIGJ5IHRoZWlyIHJlY29yZCBsZW5ndGguIFRoaXMgcHJlbGltaW5hcnkgYXNzZXNzbWVudCB3YXMgZm9sbG93ZWQgYnkgcmVwZWF0ZWQsIHJhbmRvbSBwYXJ0aXRpb25pbmcgb2YgdGhlIGRhdGEgc2V0IGludG8gdHJhaW5pbmcgYW5kIHRlc3Rpbmcgc3Vic2V0cyBjb250YWluaW5nIDgwLSBhbmQgMjAtcGVyY2VudCBvZiB0aGUgZnVsbCBkYXRhIHNldCwgcmVzcGVjdGl2ZWx5LiAgVGhlIHRlc3RpbmcgZGF0YSBzZXQgd2FzIHVzZWQgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdGhlIEdBTSBtb2RlbCBvdXRwZXJmb3JtZWQgdGhlIGNvbnN0YW50IGVzdGltYXRlZCBieSB1c2Ugb2YgdGhlIEItR0xTIG1vZGVsLiANCg0KIyMgSW5pdGlhbGl6ZSBFbnZpcm9ubWVudA0KDQpgYGB7ciBzZXR1cH0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShnZ3RoZW1lcykNCmxpYnJhcnkoa25pdHIpDQpgYGANCioqKg0KDQojIyBSZWFkIGluIFNrZXcgRGF0YSBmb3IgSFVDIFJlZ2lvbnMgMDQgYW5kIDA1DQoNCmBgYHtyIHJlYWRfZGF0YX0NCmRmIDwtIHJlYWRfdHN2KGZpbGUgPSAnQzovSG9tZS9TV19TcGVjaWFsaXN0L1NrZXcwNDA1L2RhdGEvc2tld19kYXRhLnR4dCcpICU+JSANCiAgIG11dGF0ZShTdGF0aW9uID0gcGFzdGUwKCcwJyxVU0dTKSwNCiAgICAgICAgICBSZXNpZF9za2V3X3NpZ24gPSBmYWN0b3Ioc2lnbihSZXNpZHVhbHMpKSkgJT4lIA0KICAgcmVuYW1lKFJlY29yZF9sZW4gICAgICA9IFBzZXVkb19MZW5ndGgsDQogICAgICAgICAgU3RhdGlvbl9za2V3ICAgID0gU3RhdGlvbl9Ta2V3LA0KICAgICAgICAgIFJlc2lkdWFsX3NrZXcgICA9IFJlc2lkdWFscykgDQoNCmBgYA0KDQojIyBMaXN0IFN1YnNldCBvZiBEYXRhIGFuZCBTdW1tYXJpemUNCg0KYGBge3IgbGlzdF9kYXRhLCBmaWcuY2FwID0gJ1RhYmxlIHNob3dpbmcgY29udGVudHMgb2Ygc2tldyBkYXRhIHNldCd9DQoNCmthYmxlKGRmWzE6MjAsYygnU3RhdGlvbicsJ1N0YXRpb25fc2tldycsJ1Jlc2lkdWFsX3NrZXcnLCdMYXRfQ250cmQnLCdMb25nX0NudHJkJyldLA0KICAgICAgY2FwdGlvbiA9ICdTYW1wbGUgb2YgU2tldyBSZXNpZHVhbCBEYXRhJykNCg0KIyBQcmludCBzdW1tYXJ5IG9mIA0Kc3VtbWFyeShkZikNCg0KYGBgDQoNCiMjIFBsb3QgRGlzdHJpYnV0aW9uIG9mIFN0cmVhbWdhZ2UgQ2VudHJvaXMNCg0KTm90ZTogc3ltYm9scyBkaXNjcmV0aXplIHJlc2lkdWFscyBpbnRvIHBvc2l0aXZlIGFuZCBuZWdhdGl2ZSB2YWx1ZXMNCg0KYGBge3IgY29udmVydF9jb29yZH0NCmxpYnJhcnkocmdkYWwpDQpsaWJyYXJ5KHNwKQ0KDQpwYXRoIDwtICdDOi9Ib21lL1NXX1NwZWNpYWxpc3QvU2tldzA0MDUvR0lTL1dCRF8wNV9IVTJfU2hhcGUvU2hhcGUnIA0KaHVjMl9vaGlvX3JpdmVyICA8LSByZWFkT0dSKGRzbiA9IHBhdGgsIGxheWVyID0gIldCREhVMiIpDQoNCnBhdGggPC0gJ0M6L0hvbWUvU1dfU3BlY2lhbGlzdC9Ta2V3MDQwNS9HSVMvV0JEXzA0X0hVMl9TaGFwZS9TaGFwZScNCmh1YzJfZ3JlYXRfbGFrZXMgPC0gcmVhZE9HUihkc24gPSBwYXRoLCBsYXllciA9ICJXQkRIVTIiKSANCg0KaHVjMl8wNDA1ICAgICAgICA8LSByYmluZChodWMyX2dyZWF0X2xha2VzLCBodWMyX29oaW9fcml2ZXIpDQoNCiMgSG93IHRvIGV4dHJhY3QgZGF0YWZyYW1lIGZyb20gc3BhdGlhbCBwb2x5Z29uDQpzcHAgPC0gU3BhdGlhbFBvbHlnb25zRGF0YUZyYW1lKGh1YzJfMDQwNSwgZGF0YSA9IGFzLmRhdGEuZnJhbWUoSFVDMikpDQpkZnggPC0gZGF0YS5mcmFtZShpZCA9IGdldFNwUFBvbHlnb25zSURTbG90cyhodWMyXzA0MDUpKQ0Kcm93Lm5hbWVzKGRmeCkgPC0gZ2V0U3BQUG9seWdvbnNJRFNsb3RzKGh1YzJfMDQwNSkNCnNwZGYgPC0gU3BhdGlhbFBvbHlnb25zRGF0YUZyYW1lKGh1YzJfMDQwNSwgZGF0YSA9ZGZ4KQ0KDQpodWMyXzA0MDUgJT4lIA0KICAgZ2dwbG90KCBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXApKSArDQogICBnZW9tX3BvbHlnb24oZmlsbCA9IGNvbG9ycygpWzE4XSwgY29sb3IgPSAiYmxhY2siKSArDQogICBnZW9tX3BvaW50KGRmLCBhZXMoeCA9IExvbmdfQ250cmQsIHkgPSBMYXRfQ250cmQpKQ0KDQoNCiAgIGdlb21fcG9seWdvbihodWMyX29oaW9fcml2ZXIsIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCksDQogICAgICAgICAgICAgICAgZmlsbCA9IGNvbG9ycygpWzE1XSwgY29sb3IgPSAncmVkJykNCg0KDQpmaWxsID0gY29sb3JzKClbMThdLCANCisgDQogICANCiAgIGdlb21fcG9seWdvbihkYXRhID0gc3RhdGVzX29oaW9fcml2ZXIsIA0KICAgICAgICAgICAgICAgIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCksDQogICAgICAgICAgICAgICAgZmlsbCA9IE5BLCBjb2xvciA9ICdncmV5JykgKw0KICAgZ2VvbV9wb2ludChkYXRhID0gc2tld19zaXRlcywgDQogICAgICAgICAgICAgIGFlcyggeCA9IExPTkdfQ0VOVCwgeSA9IExBVF9DRU5ULCBncm91cCA9IE5VTEwpLA0KICAgICAgICAgICAgICBjb2xvciA9ICdyZWQnLCANCiAgICAgICAgICAgICAgc2l6ZSAgPSAwLjUpICsNCiAgIGNvb3JkX21hcCgpICsNCiAgIHRoZW1lX2ZldygpICsgeGxhYignTG9uZ2l0dWRlJykgKyB5bGFiKCdMYXRpdHVkZScpIA0KDQoNCg0KDQp1c19tYXAgPC0gbWFwX2RhdGEoJ3N0YXRlJykNCg0KdXNfbWFwICU+JSANCiAgIGZpbHRlcihyZWdpb24gJWluJSBjKCdtaWNoaWdhbicsICdvaGlvJywgJ2luZGlhbmEnLCAnd2lzY29uc2luJywgJ2lsbGlub2lzJywNCiAgICAgICAgICAgICAgICAgICAgICAgICdwZW5uc3lsdmFuaWEnLCduZXcgeW9yaycsICdrZW50dWNreScsICd3ZXN0IHZpcmdpbmlhJywNCiAgICAgICAgICAgICAgICAgICAgICAgICd2ZXJtb250JykpICU+JSANCiAgIGdncGxvdCggYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwKSkgKyANCiAgIGdlb21fcG9seWdvbihmaWxsID0gJ3RhbicsIGNvbG9yID0gJ2JsYWNrJykgKyANCiAgIGdlb21fcG9seWdvbihkYXRhID0gaHVjMl8wNDA1LCBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXApLA0KICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwgY29sb3IgPSAnYmx1ZScpICsNCiAgIGdlb21fcG9pbnQoICBkYXRhID0gZGYsIGFlcyggeCA9IExvbmdfQ250cmQsIHkgPSBMYXRfQ250cmQsIGdyb3VwID0gTlVMTCksIA0KICAgICAgICAgICAgICAgIGNvbG9yID0gJ3JlZCcpICsgDQogICBjb29yZF9tYXAoJ2NvbmljJywgbGF0MCA9IDQyKSArDQogICAjIHRoZW1lX3ZvaWQoKSArICMgVGhpcyBlbGltaW5hdGVzIGxhdC9sb24gbWFya3MgDQogICB0aGVtZV9mZXcoKSArDQogICBnZW9tX3BvaW50KGRhdGEgPSBkZiwgYWVzKCB4PUxvbmdfQ250cmQsIHkgPSBMYXRfQ250cmQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gUmVzaWRfc2tld19zaWduLCBncm91cCA9IE5VTEwpKSArDQogICBzY2FsZV9jb2xvdXJfbWFudWFsKCB2YWx1ZXMgPSBjKCdyZWQnLCAnYmx1ZScpKQ0KDQoNCmBgYA0KKioqDQojIyBQcm9qZWN0IExhdGl0dWRlcyBhbmQgTG9uZ2l0dWRlcyBvZiBCYXNpbiBDZW50cm9pZHMNCg0KYGBge3IgcHJval9sYXRfbG9uZ30NCmxpYnJhcnkocmdkYWwpDQpsaWJyYXJ5KHNwKQ0KDQpkZl9wcmogIDwtIGRmDQoNCmNvb3JkaW5hdGVzKGRmX3ByaikgPC0gYygnTG9uZ19DbnRyZCcsICdMYXRfQ250cmQnKQ0KY2xhc3MoZGZfcHJqKQ0KDQpwcm9qNHN0cmluZyhkZl9wcmopIDwtICIrcHJvaj1sb25nbGF0ICtkYXR1bT1OQUQ4MyINCg0KIyBTYW1lIHRyYW5zZm9ybSBhcyANCiMgIEVQU0c6MTAyMDAzIFVTQV9Db250aWd1b3VzX0FsYmVyc19FcXVhbF9BcmVhX0NvbmljJw0KcHJval9zZWwgPC0gICdFUFNHOjEwMjAwNCBVU0FfQ29udGlndW91c19MYW1iZXJ0X0NvbmZvcm1hbF9Db25pYycNCiMgIEVQU0c6MTAyMDA1IFVTQV9Db250aWd1b3VzX0VxdWlkaXN0YW50X0NvbmljDQpkZl9wcmogPC0gc3BUcmFuc2Zvcm0oZGZfcHJqLCBDUlMgPSBDUlMoIitpbml0PWVzcmk6MTAyMDA0IikpDQoNCmVhc3RpbmcgIDwtIGF0dHJpYnV0ZXMoZGZfcHJqKSRjb29yZHNbLDFdDQpub3J0aGluZyA8LSBhdHRyaWJ1dGVzKGRmX3ByaikkY29vcmRzWywyXQ0KDQoNCnBsb3QoZWFzdGluZywgbm9ydGhpbmcsIHBjaCA9IDE2LCBjb2wgPSAnYmx1ZScpDQoNCmVhc3Rfc3RkIDwtIChlYXN0aW5nICAtIG1lYW4oZWFzdGluZyApKS8xMDAwMDANCm5ydGhfc3RkIDwtIChub3J0aGluZyAtIG1lYW4obm9ydGhpbmcpKS8xMDAwMDANCg0KcGxvdChlYXN0X3N0ZCwgbnJ0aF9zdGQsIHBjaCA9IDE2LCBjb2wgPSAnZ3JlZW40JywNCiAgICAgbWFpbiA9IHBhc3RlKCdSZWdpb25hbCBTa2V3IFN0cmVhbWdhZ2VzJyxwcm9qX3NlbCksDQogICAgIHhsYWIgPSAnU3RhbmRhcmRpemVkIEVhc3RpbmcnLCB5bGFiID0gJ1N0YW5kYXJkaXplZCBOb3J0aGluZycpDQoNCmBgYA0KYGBge3Igc2tld19kaXN0fQ0KDQpkZiAlPiUNCiAgIGdncGxvdCggYWVzKCB4ID0gU3RhdGlvbl9za2V3KSkgKw0KICAgZ2VvbV9oaXN0b2dyYW0oKSArIA0KICAgZ2VvbV92bGluZSggeGludGVyY2VwdCA9IDAsIGNvbG9yID0gJ3JlZCcsIGxpbmV0eXBlID0gJ2Rhc2hlZCcpDQoNCm5keE91dCA8LSB3aGljaChkZiRTdGF0aW9uX3NrZXcgPiAyKQ0KDQojIFJlbW92ZSBvdXRsaWVyDQoNCmRmIDwtIGRmWy1uZHhPdXQsXQ0KDQoNCmRmICU+JQ0KICAgZ2dwbG90KCBhZXMoIHggPSBTdGF0aW9uX3NrZXcpKSArDQogICBnZW9tX2ZyZXFwb2x5KCBhZXMoeSA9IC4uZGVuc2l0eS4uKSwgY29sb3IgPSAnc2FsbW9uJywgc2l6ZSA9IDEuMikgKyANCiAgIGdlb21fdmxpbmUoIHhpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICdyZWQnLCBsaW5ldHlwZSA9ICdkYXNoZWQnKSArDQogICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGRub3JtLCBhcmdzID0gbGlzdChtZWFuID0gbWVhbihkZiRTdGF0aW9uX3NrZXcpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2QgICA9ICAgc2QoZGYkU3RhdGlvbl9za2V3KSksDQogICAgICAgICAgICAgICAgIGNvbG9yID0gJ2JsdWUnKSArDQogICB0aGVtZV9mZXcoKQ0KDQpgYGANCg0KDQpgYGB7ciBnYW1fYW5hbH0NCg0KbGlicmFyeShtZ2N2KQ0KDQpkZiRlYXN0IDwtIGVhc3Rfc3RkWy1uZHhPdXRdDQpkZiRucnRoIDwtIG5ydGhfc3RkWy1uZHhPdXRdDQoNCg0KZ2FtMSA8LSBnYW0oU3RhdGlvbl9za2V3IH4gcyhlYXN0LCBucnRoKSwgd2VpZ2h0cyA9IFJlY29yZF9sZW4sIGRhdGEgPSBkZikNCg0Kc3VtbWFyeShnYW0xKQ0KDQpwbG90KGdhbTEpDQoNCmRmJGdhbV9yZXNpZCA8LSBnYW0xJHJlc2lkdWFscw0KDQpgYGANCg0KDQoNCmBgYHtyIHJlc2lkX3Bsb3R9DQoNCmRmICU+JSANCiAgIGdncGxvdCggYWVzKHggPSBnYW1fcmVzaWQpICkgKw0KICAgZ2VvbV9kZW5zaXR5KGNvbG91ciA9ICdyZWQnLCBzaXplID0gMS41KSArDQogICBnZW9tX2RlbnNpdHkoIGFlcyh4ID0gUmVzaWR1YWxfc2tldyksIGNvbG9yID0gJ2JsdWUnLCBzaXplID0gMS41KSArDQogICB0aGVtZV9mZXcoKSANCg0KdXNfbWFwICU+JSANCiAgIGZpbHRlcihyZWdpb24gJWluJSBjKCdtaWNoaWdhbicsICdvaGlvJywgJ2luZGlhbmEnLCAnd2lzY29uc2luJywgJ2lsbGlub2lzJywNCiAgICAgICAgICAgICAgICAgICAgICAgICdwZW5uc3lsdmFuaWEnLCduZXcgeW9yaycsICdrZW50dWNreScsICd3ZXN0IHZpcmdpbmlhJywNCiAgICAgICAgICAgICAgICAgICAgICAgICd2ZXJtb250JykpICU+JSANCiAgIGdncGxvdCggYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwKSkgKyANCiAgIGdlb21fcG9seWdvbihmaWxsID0gJ3RhbicsIGNvbG9yID0gJ2JsYWNrJykgKyANCiAgIGNvb3JkX21hcCgnY29uaWMnLCBsYXQwID0gNDIpICsNCiAgICMgdGhlbWVfdm9pZCgpICsgIyBUaGlzIGVsaW1pbmF0ZXMgbGF0L2xvbiBtYXJrcyANCiAgICMgdGhlbWVfZmV3KCkgKw0KICAgZ2VvbV9wb2ludChkYXRhID0gZGYsIGFlcyggeD1Mb25nX0NudHJkLCB5ID0gTGF0X0NudHJkLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGdhbV9yZXNpZCwgZ3JvdXAgPSBOVUxMKSkgKw0KICAgc2NhbGVfY29sb3VyX2dyYWRpZW50Mihsb3cgID0gInJlZCIgLCBtaWQgPSAid2hpdGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gImJsdWUiICkNCg0KDQpgYGANCg0KIyMgU2tldyBDb250b3VyIE1hcA0KDQpBIHNrZXcgY29udG91ciBtYXAgaXMgZGV2ZWxvcGVkIHRoYXQgaXMgYmFzZWQgb24gdGhlIGdhbTEgbW9kZWwgYWJvdmUuICANCg0KYGBge3IgY29udG91cl9pbmZvfQ0KDQp0bXAgIDwtIHBsb3QoZ2FtMSkNCg0KDQp4dmVjIDwtIHRtcFtbMV1dJHgNCnl2ZWMgPC0gdG1wW1sxXV0keQ0KenZlYyA8LSB0bXBbWzFdXSRmaXQNCg0KcGxvdF9seSggeCA9IGMoeHZlYyksIHkgPSBjKHl2ZWMpLA0KICAgeiA9IG1hdHJpeCh6dmVjLDQwLDQwLCBieXJvdyA9IFRSVUUpLCB0eXBlID0gJ2NvbnRvdXInLCANCiAgIGNvbnRvdXJzID0gbGlzdChzdGFydCA9IC0wLjUsIGVuZCA9IDAuNywgc2l6ZSA9IDAuMiwgc2hvd2xhYmVscyA9IFRSVUUpKSAlPiUgDQogICBhZGRfdHJhY2UodHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdtYXJrZXJzJywgeCA9IGRmJGVhc3QsIHkgPSBkZiRucnRoLCANCiAgICAgICAgICAgICAgIGNvbG9yID0gJ3JlZCcsIGhvdmVydGV4dCA9IHBhc3RlKGRmJFN0YXRpb24sIGRmJFN0YXRpb25fc2tldykpIA0KDQoNCg0KDQpgYGA=